Implement type completeness exemptions in type hint analyzer#1276
Conversation
Co-authored-by: bact <128572+bact@users.noreply.github.com>
Co-authored-by: bact <128572+bact@users.noreply.github.com>
Co-authored-by: bact <128572+bact@users.noreply.github.com>
…ndant calls Co-authored-by: bact <128572+bact@users.noreply.github.com>
Co-authored-by: bact <128572+bact@users.noreply.github.com>
Co-authored-by: bact <128572+bact@users.noreply.github.com>
Co-authored-by: bact <128572+bact@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR refines the type hint analyzer so that it aligns with the Python typing “type completeness” guidance by ignoring several categories of symbols that do not require annotations, and documents these behaviors. It reduces noise from false positives while keeping the reporting and documentation consistent with the new exemption rules.
Changes:
- Added exemption logic in
TypeHintAnalyzerfor simple-literal constants, Enum members, implicit type aliases, special module/class dunders, and__init__return types, plus supporting helpers and state tracking (e.g., Enum base detection). - Updated function analysis to treat
__init__return types as implicitly complete and extended result metadata to track whether a return annotation is present. - Expanded
build_tools/analysis/README.mdto describe the new exemption rules and how they affect function, variable, and type-alias analysis.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| build_tools/analysis/type_hint_analyzer.py | Implements the exemption rules in the analyzer, including helper methods for exempt symbols, constant detection, enum-class detection, and type-alias pattern detection, and updates function classification logic and minor lint-related annotations. |
| build_tools/analysis/README.md | Documents the analyzer’s exemption behavior and clarifies how functions, variables, enums, and type aliases are classified under the updated rules. |
|
@copilot apply changes based on the comments in this thread |
Co-authored-by: bact <128572+bact@users.noreply.github.com>
|
@copilot apply changes based on the comments in this thread |
Co-authored-by: bact <128572+bact@users.noreply.github.com>
| # 2. Union types with | operator (Python 3.10+) | ||
| if isinstance(value, ast.BinOp) and isinstance(value.op, ast.BitOr): | ||
| return True |
There was a problem hiding this comment.
The BinOp check here treats any | expression as a type-alias-like union, which will incorrectly exempt non-type assignments such as bitwise flag combinations (e.g., FLAGS = FLAG_A | FLAG_B or MASK = 1 | 2) from annotation requirements. To avoid these false positives, this branch should distinguish type unions from value-level bitwise ORs (for example by requiring that both operands look like type expressions or come from typing/typing_extensions) before treating the assignment as a type alias.
There was a problem hiding this comment.
Fixed by adding a _looks_like_type_expr() helper that checks if both operands of the | operator are type expressions. Now correctly distinguishes type unions (int | str, list[str] | None) from bitwise flag operations (FLAG_A | FLAG_B, 1 | 2). (commit 6d9e3d4)
|
@copilot apply changes based on the comments in this thread |
Co-authored-by: bact <128572+bact@users.noreply.github.com>
|



What do these changes do
Implements exemptions from Python typing documentation's type completeness guidelines in the type hint analyzer.
What was wrong
The analyzer flagged legitimate cases that don't require type annotations per PEP 561:
MAX_VALUE = 100)TypeAliasannotation__init__return types__all__,__version__, etc.)__slots__,__dict__, etc.)Additionally, the type alias detection was too broad, incorrectly exempting:
VALUE = mapping["key"]FLAGS = FLAG_A | FLAG_BorMASK = 1 | 2How this fixes it
Detection methods added:
_is_exempt_module_symbol()/_is_exempt_class_symbol()- special dunders_is_simple_literal()- only str/int/float/bool/None (excludes bytes, ellipsis)_is_constant_name()- ALL_CAPS including private (_MAX_VALUE)_is_in_enum_class()- base class tracking_looks_like_type_expr()- distinguishes type expressions from value expressions_is_type_alias_without_annotation()- conservative pattern matching with proper type/value distinctionCore logic updates:
check_function_type_hints()- exempts__init__return typesvisit_Assign()- skips all exempt variables before flaggingvisit_ClassDef()- tracks base classes for Enum detection_is_type_alias_without_annotation()- validates subscript bases are known types and checks both operands of|expressions to distinguish type unions (int | str) from bitwise operations (FLAG_A | FLAG_B)_looks_like_type_expr()- checks if expressions look like types (built-in types, typing keywords,Noneconstant, PEP 585 types) to prevent false positivesOptimizations:
_NONE_TYPE,_TYPE_ALIAS_KEYWORDS) avoid repeated computationsast.Num,ast.Str) replaced withast.ConstantCode cleanup based on review:
_has_final_annotation()helper methodtargetparameter from_is_type_alias_without_annotation()Nonein_is_simple_literal()Finalannotations)list[str]) vs value subscripts (mapping["key"])int | str,list[str] | None) vs bitwise operations (FLAG_A | FLAG_B,1 | 2)Results:
__init__exemption)Your checklist for this pull request
Original prompt
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.